//octane@neuron01:~/Documents/fall2013/cs450/dev/voltron-cs450-assignment2/jakeforkass2$ ./scenerender test.scn -0.1 -0.1 .5 0.0 -0.1 0.0 0.0 1.0 0.0
// main.cpp

#define GL3_PROTOTYPES

// Include the vector and matrix utilities from the textbook, as well as some
// macro definitions.
#include "Angel.h"

#ifdef __APPLE__
#  include <OpenGL/gl3.h>
#endif

#include <typeinfo>

#include <stdio.h>
#include <fstream>
#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
#include <vector>

#include "DebugHelper.h"
#include "ConcreteGLObject3D.h"
#include "GLScene.h"
//#include "ConcreteGLObject3D.h"
//#include "ColorContourWindow.h"

// vv need these here for the moment to compile without a bunch of changes
string scenePath;
typedef Angel::vec4  color4;
typedef Angel::vec4  point4;
GLuint  model_view;  // model-view matrix uniform shader variable location
GLuint  projection; // projection matrix uniform shader variable location
// ^^ need these here for the moment to compile without a bunch of changes

// A global constant for the number of points that will be in our object.
using namespace std;
using namespace boost;
using namespace Voltron;



// USAGE
//		scenerender	<scenefile> fx fy fz ax ay az ux uy uz
//
//			where
//			<scenefile> is a text file with a path to each object file on a separate line
//
//			fx, fy, fz are floating point components of the Eye vector
//			ax, ay, az are floating point components of the At vector
//			ux, uy, uz are floating point components of the Up vector
//
//

// globals
GLuint shaderprogram;
GLScene *_scene;
//ConcreteGLObject3D *_concretobj;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

void init()
{
	// these is just for testing the concrete object
    vec4 tempPosVertices[] = {
        vec4(-0.5, -0.5, 0.0, 1.0),
        vec4(0.5, -0.5, 0.0, 1.0),
        vec4(0.5, 0.5, 0.0, 1.0),
        vec4(-0.5, -0.5, 0.0, 1.0),
        vec4(0.5, 0.5, 0.0, 1.0),
        vec4(-0.5, 0.5, 0.0, 1.0)
    };

    vec4 tempColorVertices[] = {
        vec4(1.0, 1.0, 0.0, 1.0),
        vec4(0.0, 1.0, 0.0, 1.0),
        vec4(1.0, 0.0, 1.0, 1.0),
        vec4(1.0, 0.0, 1.0, 1.0),
        vec4(0.0, 1.0, 0.0, 1.0),
        vec4(1.0, 1.0, 0.0, 1.0)
	};


	//	_scene = new GLScene();
	//	_scene->loadSceneFromFile("test.scn");
	_scene = new GLScene();
	_scene->loadSceneFromFile(scenePath);

	shaderprogram = InitShader("vshader.glsl", "fshader.glsl");

	//_concretobj = new ConcreteGLObject3D();
	//_concretobj->loadObjectFromFile("bunnyNS.obj");
	//_concretobj = new ConcreteGLObject3D(6,tempPosVertices,tempColorVertices,shaderprogram);
	//_concretobj->initBuffers(shaderprogram);

	for (int i=0;i < _scene->_sceneObjects->size();i++)
		(*(_scene->_sceneObjects))[i]->initBuffers(shaderprogram);


///////////////////////////////////////////////////////////////////////
//// vvv THIS STUFF NEEDS TO BE WRAPPED BETTER
///////////////////////////////////////////////////////////////////////

   // Initialize shader lighting parameters
    // RAM: No need to change these...we'll learn about the details when we
    // cover Illumination and Shading
    point4 light_position( 1.5, 0.5, 2.0, 1.0 );
    color4 light_ambient( 0.2, 0.2, 0.2, 1.0 );
    color4 light_diffuse( 1.0, 1.0, 1.0, 1.0 );
    color4 light_specular( 1.0, 1.0, 1.0, 1.0 );

    color4 material_ambient( 1.0, 0.0, 1.0, 1.0 );
    color4 material_diffuse( 1.0, 0.8, 0.0, 1.0 );
    color4 material_specular( 1.0, 0.8, 0.0, 1.0 );
    float  material_shininess = 100.0;

    color4 ambient_product = light_ambient * material_ambient;
    color4 diffuse_product = light_diffuse * material_diffuse;
    color4 specular_product = light_specular * material_specular;

    glUniform4fv( glGetUniformLocation(shaderprogram, "AmbientProduct"),
		  1, ambient_product );
    glUniform4fv( glGetUniformLocation(shaderprogram, "DiffuseProduct"),
		  1, diffuse_product );
    glUniform4fv( glGetUniformLocation(shaderprogram, "SpecularProduct"),
		  1, specular_product );

    glUniform4fv( glGetUniformLocation(shaderprogram, "LightPosition"),
		  1, light_position );

    glUniform1f( glGetUniformLocation(shaderprogram, "Shininess"),
		 material_shininess );

/*
    model_view = glGetUniformLocation( shaderprogram, "ModelView" );
    projection = glGetUniformLocation( shaderprogram, "Projection" );



    mat4 p = Perspective(45, 1.0, 0.1, 10.0);
    point4  eye( atol(argv[2]), atol(argv[3].c_str()), atol(argv[4].c_str()), 1.0);
    point4  at( atol(argv[5]), atol(argv[6].c_str()), atol(argv[7].c_str()), 1.0);
    vec4    up( atol(argv[8]), atol(argv[9].c_str()), atol(argv[10].c_str()), 0.0);

 What we're going for
    point4  eye( fx, fy, fz, 1.0);
    point4  at( ax, ay, az, 1.0);
    vec4    up( ux, uy, uz, 0.0);

    mat4  mv = LookAt( eye, at, up );
    //vec4 v = vec4(0.0, 0.0, 1.0, 1.0);

    glUniformMatrix4fv( model_view, 1, GL_TRUE, mv );
    glUniformMatrix4fv( projection, 1, GL_TRUE, p );

*/
    glEnable( GL_DEPTH_TEST );

///////////////////////////////////////////////////////////////////////
//// ^^^ THIS STUFF NEEDS TO BE WRAPPED BETTER
///////////////////////////////////////////////////////////////////////

	// black background
    glClearColor( 0.0, 0.0, 0.0, 1.0 );
}

void initView(float fx,float fy,float fz,float ax,float ay,float az,float ux,float uy,float uz)
{
    model_view = glGetUniformLocation( shaderprogram, "ModelView" );
    projection = glGetUniformLocation( shaderprogram, "Projection" );

//    mat4 p = Perspective(90, 1.0, -0.1, 10.0);
    mat4 p = Perspective(90.0, 1.0, 0.1, 4.0);
    //mat4 p =  Ortho(-3, 3, -3, 3, 4, 10);
    /*
    point4  eye( atol(argv[2]), atol(argv[3].c_str()), atol(argv[4].c_str()), 1.0);
    point4  at( atol(argv[5]), atol(argv[6].c_str()), atol(argv[7].c_str()), 1.0);
    vec4    up( atol(argv[8]), atol(argv[9].c_str()), atol(argv[10].c_str()), 0.0);
    */
    
    DEBUG_PRINT(" eye( %f, %f, %f)\n",fx, fy, fz);
    DEBUG_PRINT(" at( %f, %f, %f)\n",ax, ay, az);
    DEBUG_PRINT(" up( %f, %f, %f)\n",ux, uy, uz);

    point4  eye( fx, fy, fz, 1.0);
    point4  at( ax, ay, az, 1.0);
    vec4    up( ux, uy, uz, 0.0);

    mat4  mv = LookAt( eye, at, up );
    //vec4 v = vec4(0.0, 0.0, 1.0, 1.0);

    glUniformMatrix4fv( model_view, 1, GL_TRUE, mv );
    glUniformMatrix4fv( projection, 1, GL_TRUE, p );


    glEnable( GL_DEPTH_TEST );

}


//----------------------------------------------------------------------------
void display(void)
{
    // clear the window
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	 for (int i=0;i < _scene->_sceneObjects->size();i++)
		(*(_scene->_sceneObjects))[i]->render();

    glFlush();
    glutSwapBuffers();
}

//----------------------------------------------------------------------------
void keyboard(unsigned char key, int x, int y)
{
    switch (key) {

    // Quit when ESC is pressed
    case 27:
        exit(EXIT_SUCCESS);
        break;
    }
}


int main (int argc, char *argv[])
{
	DEBUG_PRINT("main (int argc, char *argv[])\n");
	DEBUG_PRINT("argc=%d\n",argc);

	glutInit(&argc,argv);

	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitContextVersion(3,2);
	glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);

	glutInitWindowSize(512,512);
	glutInitWindowPosition(500,300);

    scenePath = string(argv[1]);

	glutCreateWindow(string("scenerender : " + scenePath).c_str());

	glewExperimental = GL_TRUE;
	glewInit();
       
//    scenePath = string(argv[1]);
	
	init();

	initView(	atof(argv[2]), atof(argv[3]), atof(argv[4]),
				atof(argv[5]), atof(argv[6]), atof(argv[7]),
				atof(argv[8]), atof(argv[9]), atof(argv[10])
	        );


	glutKeyboardFunc(keyboard);
	glutDisplayFunc(display);
	glutMainLoop();

	return 0;
}
